<!doctype html>
<html>
<head>
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
<title>React总结.md</title><link href='https://fonts.googleapis.com/css?family=PT+Serif:400,400italic,700,700italic&subset=latin,cyrillic-ext,cyrillic,latin-ext' rel='stylesheet' type='text/css'><style type='text/css'>html, body {overflow-x: initial !important;}.CodeMirror { height: auto; }
.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; }
.CodeMirror-lines { padding: 4px 0px; }
.CodeMirror pre { }
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; }
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background-color: rgb(247, 247, 247); white-space: nowrap; }
.CodeMirror-linenumbers { }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.CodeMirror div.CodeMirror-cursor { border-left: 1px solid black; z-index: 3; }
.CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; }
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0px; background: rgb(119, 238, 119); z-index: 1; }
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite { }
.cm-tab { display: inline-block; }
.cm-s-typora-default .cm-header, .cm-s-typora-default .cm-property { color: rgb(217, 79, 138); }
.cm-s-typora-default pre.cm-header1:not(.cm-atom) :not(.cm-overlay) { font-size: 2rem; line-height: 2rem; }
.cm-s-typora-default pre.cm-header2:not(.cm-atom) :not(.cm-overlay) { font-size: 1.4rem; line-height: 1.4rem; }
.cm-s-typora-default .cm-atom, .cm-s-typora-default .cm-number { color: rgb(149, 132, 134); }
.cm-s-typora-default .cm-table-row, .cm-s-typora-default .cm-block-start { font-family: monospace; }
.cm-s-typora-default .cm-comment, .cm-s-typora-default .cm-code { color: rgb(74, 90, 159); font-family: monospace; }
.cm-s-typora-default .cm-tag { color: rgb(169, 68, 66); }
.cm-s-typora-default .cm-string { color: rgb(126, 134, 169); }
.cm-s-typora-default .cm-link { color: rgb(196, 122, 15); text-decoration: underline; }
.cm-s-typora-default .cm-variable-2, .cm-s-typora-default .cm-variable-1 { color: inherit; }
.cm-s-typora-default .cm-overlay { font-size: 1rem; font-family: monospace; }
.CodeMirror.cm-s-typora-default div.CodeMirror-cursor { border-left: 3px solid rgb(228, 98, 154); }
.cm-s-typora-default .CodeMirror-activeline-background { left: -60px; right: -30px; background: rgba(204, 204, 204, 0.2); }
.cm-s-typora-default .CodeMirror-gutters { border-right: none; background-color: inherit; }
.cm-s-typora-default .cm-trailing-space-new-line::after, .cm-startspace::after, .cm-starttab .cm-tab::after { content: "•"; position: absolute; left: 0px; opacity: 0; font-family: LetterGothicStd, monospace; }
.os-windows .cm-startspace::after, .os-windows .cm-starttab .cm-tab::after { left: -0.1em; }
.cm-starttab .cm-tab::after { content: " "; }
.cm-startspace, .cm-tab, .cm-starttab, .cm-trailing-space-a, .cm-trailing-space-b, .cm-trailing-space-new-line { font-family: monospace; position: relative; }
.cm-s-typora-default .cm-trailing-space-new-line::after { content: "↓"; opacity: 0.3; }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: black; }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-property { color: black; }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: blue; }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: bold; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error { color: rgb(255, 0, 0); }
.cm-invalidchar { color: rgb(255, 0, 0); }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.cm-s-inner .CodeMirror-activeline-background { background: inherit; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; padding-right: 30px; height: 100%; outline: none; position: relative; box-sizing: content-box; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow-x: hidden; overflow-y: scroll; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow-y: hidden; overflow-x: scroll; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-radius: 0px; border-width: 0px; background: transparent; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-widget { }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.CodeMirror-selected { background: rgb(217, 217, 217); }
.CodeMirror-focused .CodeMirror-selected { background: rgb(215, 212, 240); }
.cm-searching { background: rgba(255, 255, 0, 0.4); }
.CodeMirror span { }
@media print { 
  .CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}
.CodeMirror-lint-markers { width: 16px; }
.CodeMirror-lint-tooltip { background-color: infobackground; border: 1px solid black; border-radius: 4px; color: infotext; font-family: monospace; overflow: hidden; padding: 2px 5px; position: fixed; white-space: pre-wrap; z-index: 10000; max-width: 600px; opacity: 0; transition: opacity 0.4s; font-size: 0.8em; }
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; }
.CodeMirror-lint-mark-error { background-image: url(""); }
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { background-position: center center; background-repeat: no-repeat; cursor: pointer; display: inline-block; height: 16px; width: 16px; vertical-align: middle; position: relative; }
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { padding-left: 18px; background-position: left top; background-repeat: no-repeat; }
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url(""); }
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url(""); }
.CodeMirror-lint-marker-multiple { background-image: url(""); background-repeat: no-repeat; background-position: right bottom; width: 100%; height: 100%; }


html { font-size: 14px; background-color: rgb(255, 255, 255); color: rgb(51, 51, 51); }
body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; }
a:active, a:hover { outline: 0px; }
.in-text-selection, ::selection { background: rgb(181, 214, 252); text-shadow: none; }
#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; padding-bottom: 70px; white-space: pre-wrap; overflow-x: auto; }
.for-image #write { padding-left: 8px; padding-right: 8px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
@media screen and (max-width: 500px) { 
  body.typora-export { padding-left: 0px; padding-right: 0px; }
  .CodeMirror-sizer { margin-left: 0px !important; }
  .CodeMirror-gutters { display: none !important; }
}
.typora-export #write { margin: 0px auto; }
#write > p:first-child, #write > ul:first-child, #write > ol:first-child, #write > pre:first-child, #write > blockquote:first-child, #write > div:first-child, #write > table:first-child { margin-top: 30px; }
#write li > table:first-child { margin-top: -20px; }
img { max-width: 100%; vertical-align: middle; }
input, button, select, textarea { color: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
::before, ::after, * { box-sizing: border-box; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write div, #write pre { width: inherit; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6 { position: relative; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
p { -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }
.mathjax-block { margin-top: 0px; margin-bottom: 0px; -webkit-margin-before: 0rem; -webkit-margin-after: 0rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: bold; font-style: italic; }
a { cursor: pointer; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; margin: 4px 0px 0px; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 80px; }
.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
pre { white-space: pre-wrap; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
.md-fences .CodeMirror.CodeMirror-wrap { top: -1.6em; margin-bottom: -1.6em; }
.md-fences.mock-cm { white-space: pre-wrap; }
.show-fences-line-number .md-fences { padding-left: 0px; }
.show-fences-line-number .md-fences.mock-cm { padding-left: 40px; }
.footnotes { opacity: 0.8; font-size: 0.9rem; padding-top: 1em; padding-bottom: 1em; }
.footnotes + .footnotes { margin-top: -1em; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: transparent; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: normal; text-align: left; box-sizing: content-box; direction: ltr; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li p, li .mathjax-block { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; }
@media print { 
  html, body { height: 100%; }
  .typora-export * { -webkit-print-color-adjust: exact; }
  h1, h2, h3, h4, h5, h6 { break-after: avoid-page; orphans: 2; }
  p { orphans: 4; }
  html.blink-to-pdf { font-size: 13px; }
  .typora-export #write { padding-left: 1cm; padding-right: 1cm; }
  .typora-export #write::after { height: 0px; }
  @page { margin: 20mm 0mm; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 2.86rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
p .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.mathjax-block { white-space: pre; overflow: hidden; width: 100%; }
p + .mathjax-block { margin-top: -1.143rem; }
.mathjax-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: none; box-shadow: none; }
.task-list { list-style-type: none; }
.task-list-item { position: relative; padding-left: 1em; }
.task-list-item input { position: absolute; top: 0px; left: 0px; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc::after, .md-toc-content::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); text-decoration: none; }
.md-toc-inner:hover { }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: bold; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) { 
  .md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
  .md-toc-h4 .md-toc-inner { margin-left: 5em; }
  .md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
  .md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
.md-tag { opacity: 0.5; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: monospace; }
code { text-align: left; }
h1 .md-tag, h2 .md-tag, h3 .md-tag, h4 .md-tag, h5 .md-tag, h6 .md-tag { font-weight: initial; opacity: 0.35; }
a.md-print-anchor { border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: none !important; background: transparent !important; text-decoration: initial !important; text-shadow: initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.mathjax-block .MathJax_SVG_Display { text-align: center; margin: 1em 0em; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: monospace; }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: normal; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none; }


@font-face { font-family: "PT Serif"; font-style: normal; font-weight: normal; src: local("PT Serif"), local("PTSerif-Regular"), url("./newsprint/PT_Serif-Web-Regular.ttf"); }
@font-face { font-family: "PT Serif"; font-style: italic; font-weight: normal; src: local("PT Serif"), local("PTSerif-Italic"), url("./newsprint/PT_Serif-Web-Italic.ttf"); }
@font-face { font-family: "PT Serif"; font-style: normal; font-weight: bold; src: local("PT Serif"), local("PTSerif-Bold"), url("./newsprint/PT_Serif-Web-Bold.ttf"); }
@font-face { font-family: "PT Serif"; font-style: italic; font-weight: bold; src: local("PT Serif"), local("PTSerif-BoldItalic"), url("./newsprint/PT_Serif-Web-BoldItalic.ttf"); }
html { font-size: 16px; }
html, body { background-color: rgb(243, 242, 238); font-family: "PT Serif", "Times New Roman", Times; color: rgb(31, 9, 9); line-height: 1.5em; }
#write { max-width: 40em; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote::before, blockquote::after, q::before, q::after { content: none; }
table { border-collapse: collapse; border-spacing: 0px; }
h1, h2, h3, h4, h5, h6 { font-weight: bold; }
h1 { font-size: 1.875em; line-height: 1.6em; margin-top: 2em; }
h2, h3 { font-size: 1.3125em; line-height: 1.15; margin-top: 2.28571em; margin-bottom: 1.15em; }
h3 { font-weight: normal; }
h4 { font-size: 1.125em; margin-top: 2.67em; }
h5, h6 { font-size: 1em; }
h1 { border-bottom: 1px solid; margin-bottom: 1.875em; padding-bottom: 0.8125em; }
a { text-decoration: none; color: rgb(6, 85, 136); }
a:hover, a:active { text-decoration: underline; }
p, blockquote, .md-fences { margin-bottom: 1.5em; }
h1, h2, h3, h4, h5, h6 { margin-bottom: 1.5em; }
blockquote { font-style: italic; border-left: 5px solid; margin-left: 2em; padding-left: 1em; }
ul, ol { margin: 0px 0px 1.5em 1.5em; }
ol li { list-style-type: decimal; list-style-position: outside; }
ul li { list-style-type: disc; list-style-position: outside; }
.md-meta, .md-before, .md-after { color: rgb(153, 153, 153); }
table { margin-bottom: 1.5em; font-size: 1em; }
thead th, tfoot th { padding: 0.25em 0.25em 0.25em 0.4em; text-transform: uppercase; }
th { text-align: left; }
td { vertical-align: top; padding: 0.25em 0.25em 0.25em 0.4em; }
code, .md-fences { background-color: rgb(218, 218, 218); padding-left: 1ch; padding-right: 1ch; }
.md-fences { margin-left: 2em; margin-bottom: 3em; }
.md-fences .CodeMirror.CodeMirror-wrap { top: -0.8em; }
pre, code, tt { font-size: 0.875em; line-height: 1.71428em; }
h1 { line-height: 1.3em; font-weight: normal; margin-bottom: 0.5em; }
p + ul, p + ol { margin-top: -1em; }
h3 + ul, h4 + ul, h5 + ul, h6 + ul, h3 + ol, h4 + ol, h5 + ol, h6 + ol { margin-top: 0.5em; }
li > ul, li > ol { margin-top: inherit; }
h2, h3 { margin-bottom: 0.75em; }
hr { border-top: none; border-right: none; border-bottom: 1px solid; border-left: none; }
h1 { border-color: rgb(197, 197, 197); }
blockquote { border-color: rgb(186, 186, 186); color: rgb(101, 101, 101); }
thead.md-table-edit { background-color: transparent; }
thead { background-color: rgb(218, 218, 218); }
tr:nth-child(2n) { background: rgb(232, 231, 231); }
hr { border-color: rgb(197, 197, 197); }
.task-list { padding-left: 1rem; }
.task-list-item { padding-left: 1.5rem; list-style-type: none; }
.task-list-item input::before { content: "√"; display: inline-block; width: 1.25rem; height: 1.6rem; vertical-align: middle; text-align: center; color: rgb(221, 221, 221); background-color: rgb(243, 242, 238); }
.task-list-item input:checked::before, .task-list-item input[checked]::before { color: inherit; }
#write pre.md-meta-block { min-height: 1.875rem; color: rgb(85, 85, 85); border: 0px; background: transparent; margin-left: 1em; margin-top: 1em; }
.md-image > .md-meta { color: rgb(155, 81, 70); }
.md-expand.md-image > .md-meta { background-color: rgba(255, 255, 255, 0.65098); }
.md-image > .md-meta { font-family: Menlo, "Ubuntu Mono", Consolas, "Courier New", "Microsoft Yahei", "Hiragino Sans GB", "WenQuanYi Micro Hei", sans-serif; }
#write > h3.md-focus::before { left: -1.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h4.md-focus::before { left: -1.5rem; top: 0.25rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h5.md-focus::before { left: -1.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h6.md-focus::before { left: -1.5rem; top: 0.3125rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
.md-toc:focus .md-toc-content { margin-top: 19px; }
.md-toc-content:empty::before { color: rgb(6, 85, 136); }
.md-toc-item { color: rgb(6, 85, 136); }
#write div.md-toc-tooltip { background-color: rgb(243, 242, 238); }
#outline-dropmenu { background-color: rgb(243, 242, 238); box-shadow: rgba(0, 0, 0, 0.372549) 0px 6px 12px; }
.pin-outline #outline-dropmenu { background: inherit; box-shadow: none; border-right: 1px dashed; }
.pin-outline #outline-dropmenu:hover .outline-title-wrapper { border-left: 1px dashed; }
.outline-item:hover { background-color: rgb(218, 218, 218); border-left: 28px solid rgb(218, 218, 218); border-right: 18px solid rgb(218, 218, 218); }
.typora-node .outline-item:hover { border-right: 28px solid rgb(218, 218, 218); }
.outline-expander::before { content: ""; font-family: FontAwesome; font-size: 14px; top: 1px; }
.outline-expander:hover::before, .outline-item-open > .outline-item > .outline-expander::before { content: ""; }
.modal-content { background-color: rgb(243, 242, 238); }
.auto-suggest-container ul li { list-style-type: none; }
.megamenu-menu, #top-titlebar, #top-titlebar *, .megamenu-content { background: rgb(243, 242, 238); color: rgb(31, 9, 9); }
.megamenu-menu-header { border-bottom: 1px dashed rgb(32, 43, 51); }
.megamenu-menu { box-shadow: none; border-right: 1px dashed; }
header, .context-menu, .megamenu-content, footer { font-family: "PT Serif", "Times New Roman", Times; color: rgb(31, 9, 9); }
#megamenu-back-btn { color: rgb(31, 9, 9); border-color: rgb(31, 9, 9); }
.megamenu-menu-header #megamenu-menu-header-title::before { color: rgb(31, 9, 9); }
.megamenu-menu-list li a:hover, .megamenu-menu-list li a.active { color: inherit; background-color: rgb(232, 231, 223); }
.long-btn:hover { background-color: rgb(232, 231, 223); }
#recent-file-panel tbody tr:nth-child(2n-1) { background-color: transparent !important; }
.megamenu-menu-panel tbody tr:hover td:nth-child(2) { color: inherit; }
.megamenu-menu-panel .btn { background-color: rgb(210, 209, 209); }
.btn-default { background-color: transparent; }
.typora-sourceview-on #toggle-sourceview-btn, .show-word-count #footer-word-count { background: rgb(199, 197, 197); }
#typora-quick-open { background-color: inherit; }
.md-diagram-panel { margin-left: -1ch; margin-top: 24px; }






</style>
</head>
<body class='typora-export' >
<div  id='write'  class = 'is-node'><p></p><h1><a name='header-c7' class='md-header-anchor '></a>移动App第1天</h1><h2><a name='header-c33' class='md-header-anchor '></a>什么是混合移动App开发【重点】</h2><ol><li>苹果上的软件是如何开发出来的：使用的是 OC、或者使用Swift这门语言</li><li>安卓平台上的软件又是如何开发出来的：使用安卓相关的语言开发的，Java，安卓的控件进行开发</li><li>苹果和安卓平台上共有的软件是如何开发出来的：腾讯招两套开发人员【开发组】，手机京东</li><li>前端移动 App（Application）开发技术，去开发手机端的应用程序；</li><li>前端的混合移动App开发技术，并没有使用 苹果 或 安卓 官方推荐的 开发平台和开发方式，而是抛弃了 官方提供的方式，使用 前端的独有的技术进行移动App开发体验；</li></ol><blockquote><p>什么是移动App开发：通俗的理解，就是把开发Web网站的技术（HTML+CSS+JS），通过某种方式，移植到移动App开发上进行使用，这种利用Web开发技术进行移动端开发体验的方式，叫做混合移动App开发！</p></blockquote><h3><a name='header-c53' class='md-header-anchor '></a>关于移动App开发，需要知道的几个概念：</h3><ul><li><p>原生开发：它的英文单词是（NativeApp）,指的就是使用 IOS、Android 官方提供的工具、开发平台、配套语言进行 手机App开发的方式；</p></li><li><p>混合开发：（HybirdApp）就是使用前端已有的技术，HTML + CSS + JS ，然后再搭配一些相关的打包编译技术，就能够开发出一个手机App，安装到手机中进行使用；</p></li><li><p>什么是App：App是（Application的缩写），意思是：可安装的应用程序；</p></li><li><p>App的分类：</p><ul><li><p>按照平台来划分：</p><ul><li>PC端：浏览器、代码编辑器、PC端的游戏、听歌的、看视频的、聊天的</li><li>移动端：手机QQ、手机微信、手机爱奇艺、亡者农药</li></ul></li><li><p>按照功能来划分：</p><ul><li>游戏：愤怒的小鸡仔、植物大战僵尸、亡者农药.....LOL</li><li>应用：非游戏类的软件，支付宝、陌陌、美团外卖、</li></ul></li></ul></li><li><p>App和Web的区别：</p><ul><li>APP概念：App是（Application的缩写），意思是：可安装的应用程序；</li></ul><ul><li>优点：流畅、稳定、基本上一些App都可以脱网运行，用户体验好；</li><li>缺点：不能跨平台</li></ul><ul><li>Web概念：特指那些基于浏览器的web网站（本质：就是网页）</li></ul><ul><li>优点：可以跨平台（浏览器天生就是跨平台的）</li><li>缺点：没有App流畅、不稳定，受限于网速和网络</li></ul></li></ul><h2><a name='header-c113' class='md-header-anchor '></a>为什么要学混合App开发</h2><h3><a name='header-c114' class='md-header-anchor '></a>从程序员的角度分析：</h3><ol><li>挣钱多（别人不会的你会，别人会的，你精通）</li><li>对于找工作来说：（React Native）市场需求量大，好找工作，提高我们的行业竞争力</li><li>能接触到前端流行的技术和框架（各大公司基本都再用React），注意：再React中我们全部都使用ES6语法（class）</li></ol><ul><li>前端是一个永恒的行业???（只要世界上还有浏览器的存在，必然需要前端，只不过，随着时间的推移，技术更新换代，可能我们对新技术的要求会越来高）</li><li>屌丝的崛起之路：<code>只能做页面</code> -&gt; <code>Ajax前后台数据交互</code> -&gt; <code>Jquery、Bootstrap</code> -&gt; webApp -&gt; <code>三大框架</code> -&gt; <code>可以做手机混合App/桌面应用</code> -&gt; <code>可以做手机原生App</code> -&gt; <code>将来或许可以发射火箭发射卫星发射导弹</code> -&gt; <code>终极目标：统一全宇宙</code></li></ul><ol><li>（搞前端App开发）能购置一批牛逼的设备【苹果笔记本、IOS测试机、安卓手机（三星的、华为、小米）】</li></ol><h3><a name='header-c136' class='md-header-anchor '></a>从企业的角度分析:(选择合适自身的移动App开发方式)【重点】</h3><ul><li>节省开发成本</li></ul><ul><li>从工资上：尽最大的可能，压榨员工的剩余劳动力</li><li>从时间上：因为 原生的安卓和IOS开发，它们的开发效率并不是很高，因为原生的代码复杂度比较高，因此原生的开发周期比较慢；如果采用移动App开发，那么，我们的开发周期会很短；因为 HTML + CSS + JS 足够简单；（对于前端开发APP来说，有两种方式，其中，比较早的一种，也是比较简单的一种，就是 先开发出一个网站， 然后再把网站运行一行打包的命令，就能得到一个 APP了）</li></ul><ol><li>市面上常见的App开发方式</li></ol><ul><li><p>WebApp：基于浏览器实现的，有特定功能的网站，称作WebApp</p><ul><li><p>例如：百度脑图、<a href='https://m.jd.com/' target='_blank' >https://m.jd.com/</a>、<a href='https://m.taobao.com/#index' target='_blank' >https://m.taobao.com/#index</a></p><ul><li>优点：跨平台</li><li>缺点：依赖网络，有白屏效果，相对来说，用户体验差；不能调用硬件底层得设备，比如摄像头；</li></ul></li></ul></li><li><p>NativeApp：用android和Object-C等原生语言开发的应用</p><ul><li>优点：体验好；用户使用起来很流畅；非常适合做游戏【性能高】；可以直接调用硬件底层的API；</li><li>缺点：不能跨平台</li></ul></li><li><p>HybirdApp：利用前端所学的知识去开发移动端App，兼具2者的优势</p><ul><li>优点：能够跨平台；体验会好一些；也能够调用硬件底层的API</li><li>缺点：相对于原生体验稍微弱一丢丢；不适合做游戏；适合做非游戏类型的手机App；</li><li>应用场景：</li></ul></li><li><p>注意： 使用 Java 或者 IOS 写出来的代码和程序，在最终运行的时候，普通的文本代码，都会被编译为 原生的机器码去运行，并不像 JS 这样，解析执行，Java代码是 编译执行的；</p></li></ul><ol><li>三种开发方式的原理和对比
<img src='images/%E4%B8%89%E7%A7%8D%E5%BC%80%E5%8F%91%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8E%9F%E7%90%86.png' alt='' />
<img src='images/%E4%B8%89%E7%A7%8D%E5%BC%80%E5%8F%91%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AF%B9%E6%AF%94.png' alt='' /></li><li><a href='https://facebook.github.io/react-native/showcase.html'>谁在使用React Native？？？</a></li></ol><h2><a name='header-c202' class='md-header-anchor '></a>企业如何选择合适自己的App开发方式</h2><ol><li>如果这个企业中，曾经使用原生技术开发过一些APP，那么在维护的时候，必然需要使用原生技术来维护</li><li>如果企业中，需要做一些游戏级别的应用，那么推荐使用原生，因为原生运行效率高，对耗电量处理的很好；</li><li>如果企业做一些应用级别的非游戏软件，比如 淘宝、京东、美团，就可以使用 混合APP了；</li><li>在企业中，最主要的是好的点子，如果有了一个好的项目立案，那么最好要立即把这个项目做出来；这时候，使用混合App非常合适，因为开发周期很短，能快速上线，抢先占领市场；【裤衩开发】</li></ol><h2><a name='header-c216' class='md-header-anchor '></a>企业中项目开发流程</h2><ul><li>需求调研：产品定位、受众群体、市场需求、开发价值；【产出物：需求文档】</li><li>产品设计：功能模块、流程逻辑；【产出物：设计文档，交互稿】，确定项目的基本功能；</li><li>项目开发：项目架构、美工、前端、后台、测试【产品的把控】<strong>要理解前后端分离的概念</strong></li><li>运营维护：上线试运行、调Bug、微调功能模块、产品迭代</li></ul><blockquote><p>根据需求搞设计，根据设计做开发</p></blockquote><h2><a name='header-c233' class='md-header-anchor '></a>企业技术选型 - 几大主流技术之间的关系</h2><ol><li>Angular.js 和 Ionic</li></ol><ul><li><a href='https://angularjs.org/'>Angular1官网</a></li><li><a href='https://angular.io/'>Angular2官网</a></li><li><a href='http://www.ionic.wang/'>Ionic 中文网</a></li><li><a href='http://ionicframework.com/getting-started/'>Ionic 英文官网</a></li></ul><ol><li>Vue.js 和 Weex</li></ol><ul><li><a href='https://cn.vuejs.org/'>Vue.js官网</a></li><li><a href='http://weex.apache.org/cn/references/index.html'>Weex文档</a></li><li><a href='https://github.com/apache/incubator-weex'>Weex - github地址 - 新</a></li><li><a href='https://github.com/alibaba/weex'>Weex - github地址 - 旧</a></li></ul><ol><li>React.js 和 React-Native</li></ol><ul><li><a href='https://facebook.github.io/react/'>React.js英文官网</a></li><li><a href='http://reactnative.cn/'>ReactNative中文网</a></li><li><a href='http://facebook.github.io/react-native/'>ReactNative英文网</a></li></ul><blockquote><p>Angular, Vue, React 这三个都是前端框架，我们在进行混合App开发的时候，只是用到了这三个框架的【基础语法】而已；
Ionic， Weex， ReactNatvie 这三个都是打包工具（提供了相关的命令行，只要运行指定的命令，就能够把项目打包成一个手机App出来），能够把我们开发出来的应用，最终打包成一个可安装的手机端程序安装包；同时，这三个东西，也提供了好用的一些小组件，方便我们去构建移动App的用户界面；</p></blockquote><h2><a name='header-c286' class='md-header-anchor '></a>前端混合App开发框架</h2><ol><li>Html5+、ReactNative、Weex、Ionic</li><li><a href='http://www.html5plus.org/#home'>认识HTML5+</a></li></ol><ul><li>h5+是一个产业联盟，它有一些互联网成员，专门在中国推广H5</li></ul><ol><li><a href='http://www.dcloud.io/'>HBuilder官网</a></li></ol><h2><a name='header-c302' class='md-header-anchor '></a>开发框架之间的区别</h2><ol><li>Html5+ 和 Ionic</li><li>ReactNative 和 Weex</li></ol><h2><a name='header-c310' class='md-header-anchor '></a>使用HBuilder生成安卓应用（在线）</h2><p><a href='http://www.html5plus.org/doc/zh_cn/webview.html'>API地址</a>
Hbuilder这个工具，是一个在线打包工具，使用很方便，不需要在本地配置开发环境；直接将做好的网站，通过一些简单的操作，就能在线打包为一个App出来；</p><ul><li>在项目上右键 -&gt; 发行 -&gt; 发行为原生安装包</li></ul><p>好处：本地不用配置开发环境；操作方便，对于程序员来说不关心打包的过程，打包过程对于我们来说是透明的；
缺点：程序员很少能干预打包的过程；源代码被提交到了云端的服务器，存在项目核心代码被泄露的风险；</p><h2><a name='header-c321' class='md-header-anchor '></a>环境变量的使用</h2><p>作用：将需要全局使用的工具或者应用程序，配置到Path环境变量中，可以很方便的通过命令行的形式，在任何想要运行这些应用程序的地方，运行它们；</p><h2><a name='header-c324' class='md-header-anchor '></a>移动App开发环境配置【重点】</h2><h3><a name='header-c325' class='md-header-anchor '></a>安装最新版本的java jdk</h3><ol><li>修改环境变量，新增<code>JAVA_HOME</code>的系统环境变量，值为<code>C:\Program Files (x86)\Java\jdk1.8.0_112</code>，也就是安装JDK的根目录</li><li>修改系统环境变量<code>Path</code>，在<code>Path</code>之后新增<code>%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;</code></li><li>新建<strong>系统环境变量</strong><code>CLASSPATH</code>，值为<code>.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;</code></li><li>保存所有的系统环境变量，同时退出系统环境变量配置窗口，然后运行cmd命令行工具，输入<code>javac</code>，如果能出现javac的命令选项，就表示配置成功！</li></ol><h3><a name='header-c339' class='md-header-anchor '></a>安装Node.js环境</h3><p>注意：需要安装最新的长期稳定版本，不要实验版本；安装完毕之后的node.js会自动配置到全局系统环境变量中
安装完毕后，可以输入<code>node -v</code>查看node版本号；</p><h3><a name='header-c343' class='md-header-anchor '></a>安装C++环境</h3><p>大多数情况下操作系统自带C++环境，不需要手动安装C++环境；
如果运行报错，则需要手动安装visual studio中的C++环境；</p><h3><a name='header-c347' class='md-header-anchor '></a>安装Git环境</h3><p>Git安装完毕后，会自动配置到系统环境变量中；
可以通过运行<code>git --version</code>来检查是否正确安装和配置了Git的环境变量；</p><h3><a name='header-c351' class='md-header-anchor '></a>安装Python环境</h3><ol><li>注意：安装Python时候，只能<strong>安装2.×的版本</strong>，注意勾选安装界面上的<code>Add Python to path</code>，这样才能自动将Python安装到系统环境变量中；</li><li>安装完毕之后，可以在命令行中运行<code>python</code>，检查是否成功安装了python。</li></ol><h3><a name='header-c359' class='md-header-anchor '></a>配置安卓环境</h3><ol><li>安装<code>installer_r24.3.4-windows.exe</code>，最好手动选择安装到C盘下的android目录</li><li>打开安装的目录，将<code>android-25</code>、<code>android-23</code>(react-native必须依赖这个)解压后，放到<code>platforms</code>文件夹下</li><li>解压<code>platform-tools</code>，放到<code>platform-tools</code>文件夹下</li><li>【这一步直接忽略即可！】<strong>tools文件夹不解压覆盖也行；</strong><del>解压<code>tools</code>，放到安装根目录中</del></li><li>解压<code>build-tools_r23.0.1-windows.zip(react-native必须依赖这个)</code>、<code>build-tools_r23.0.2-windows.zip(weex必须依赖这个)</code>和<code>build-tools_r23.0.3-windows.zip</code>，并将解压出来的文件夹，分别改名为版本号<code>23.0.1</code>、<code>23.0.2</code>和<code>23.0.3</code>；在安装目录中新建文件夹<code>build-tools</code>，并将改名为版本号之后的文件夹，放到新创建出来的<code>build-tools</code>文件夹下</li><li>在安装目录中，新建<code>extras</code>文件夹，在<code>extras</code>文件夹下新建<code>android</code>文件夹；解压<code>m2responsitory</code>文件夹和<code>support</code>文件夹，放到新建的<code>extras -&gt; android</code>文件夹下</li><li>配置安装环境变量：在系统环境变量中新建<code>ANDROID_HOME</code>，值为android SDK Manager的安装路径<code>C:\Users\liulongbin\AppData\Local\Android\android-sdk</code>，紧接着，在Path中新增<code>;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;</code></li></ol><h2><a name='header-c382' class='md-header-anchor '></a><a href='http://reactnative.cn/docs/0.42/getting-started.html'>ReactNative快速打包</a></h2><ol><li>安装完node后建议<strong>设置npm镜像</strong>以加速后面的过程（或使用科学上网工具）。注意：<strong>不要使用cnpm！</strong>cnpm安装的模块路径比较奇怪，packager不能正常识别！</li></ol><blockquote><p>npm config set registry <a href='https://registry.npm.taobao.org' target='_blank' >https://registry.npm.taobao.org</a> --global<br/>
npm config set disturl <a href='https://npm.taobao.org/dist' target='_blank' >https://npm.taobao.org/dist</a> --global</p></blockquote><ol><li>Yarn、React Native的命令行工具（react-native-cli）</li></ol><ul><li><p>Yarn是Facebook提供的替代npm的工具，可以加速node模块的下载。React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务（packager）等任务。</p><blockquote><p>npm install -g yarn react-native-cli</p></blockquote></li><li><p>安装完yarn后同理也要设置镜像源：</p><blockquote><p>yarn config set registry <a href='https://registry.npm.taobao.org' target='_blank' >https://registry.npm.taobao.org</a> --global<br/>
yarn config set disturl <a href='https://npm.taobao.org/dist' target='_blank' >https://npm.taobao.org/dist</a> --global</p></blockquote></li></ul><ol><li><p>运行<code>react-native init AwesomeProject</code>创建React-Native项目</p></li><li><p>运行<code>cd AwesomeProject</code>切换到项目根目录中，运行<code>adb devices</code>来确保有设备连接到了电脑上</p><pre class='md-fences mock-cm' style='display:block;position:relative'>一般安装了Hbuilder的都会有adb，将它的绝对路径配置到path环境变量即可</pre><p>​</p></li><li><p>运行<code>react-native run-android</code>打包编译安卓项目，并部署到模拟器或开发机中</p><pre class='md-fences mock-cm' style='display:block;position:relative'> unable to load script from asset/index.android.bundle问题解决：
 原因：assets中没有成功打包出index.android.bundle文件
　　解决：1.去（你的项目文件夹）\android\app\src\main目录下新建asset文件夹
　　　　　2.终端下运行
　　　　　react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
　　　　　3.再次执行 react-native run-android
注：由于0.49版本以后的react-native没有index.android.js和index.ios.js文件，而统一合并成了index.js，所以使用0.49及以后版本的同学请将第2步中的入口文件改为index.js
		 react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

附上解决方式原贴：https://stackoverflow.com/questions/44446523/unable-to-load-script-from-assets-index-android-bundle-on-windows</pre><p>​</p><p>​</p></li><li><p>运行上一条命令之前，要确保有设备连接到了电脑上，可以运行<code>adb devices</code>查看当前接入的设备列表，打包好的文件，放到了<code>android\app\build\outputs\apk</code>目录下</p></li><li><p><a href='http://www.open-open.com/lib/view/open1477469117948.html'>入坑指南</a></p></li></ol><blockquote><p><strong>问题1：开启悬浮框权限；</strong><br/>
<strong>问题2：Could not get BatchedBridge, make sure your bundle is packaged correctly</strong><br/>
解决方案：在终端中，进入到项目的根目录，执行下面这段命令行：<br/>
<code>react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/</code><br/>
运行之前，需要确保<code>android/app/src/main/</code>目录下有<code>assets</code>文件夹，如果没有，手动创建之~，再运行上面的命令；<br/>
<strong>问题3：could not connect to development server</strong><br/>
解决方案：晃动手机，唤起设置属性窗口，点击“Dev settings”，再点击Debuug server host 出现设置ip地址窗口，填写Ip地址和端口号8081，例如<code>192.168.1.111:8081</code></p></blockquote><h2><a name='header-c442' class='md-header-anchor '></a><a href='http://weex.apache.org/cn/guide/tools/toolkit.html'>Weex快速打包</a></h2><ol><li><p>安装依赖:Weex 官方提供了 weex-toolkit 的脚手架工具来辅助开发和调试。首先，你需要最新稳定版的 Node.js 和 Weex CLi。</p></li><li><p>运行<code>npm install -g weex-toolkit</code>安装Weex 官方提供的 <code>weex-toolkit</code> 脚手架工具到全局环境中</p><pre class='md-fences mock-cm' style='display:block;position:relative'>使用npm4 才支持
npm install npm@4 -g</pre><p>​</p></li><li><p>运行<code>weex create project-name</code>初始化Weex项目</p></li><li><p>进入到项目的根目录中，打开cmd窗口，运行<code>weex platform add android</code>安装android模板，首次安装模板时，等待时间较长，建议fq安装模板</p></li><li><p>打开<code>android studio</code>中的<code>安卓模拟器</code>，或者将<code>启用USB调试的真机</code>连接到电脑上，运行<code>weex run android</code>，打包部署weex项目</p></li><li><p>部署完成，查看项目效果</p></li></ol><p>没有自动更新</p><h2><a name='header-c467' class='md-header-anchor '></a>总结重点</h2><ol><li>什么是前端移动App开发</li><li>市面上常见的App开发方式及优缺点</li><li>使用Hbuilder在线生成安卓应用</li><li>学会配置ReactNative开发环境</li><li>掌握ReactNative打包流程</li></ol><p></p><h2><a name='header-c28' class='md-header-anchor '></a>移动App第2天</h2><h2><a name='header-c487' class='md-header-anchor '></a>webpack的发布策略</h2><ol><li>在实际开发中，一般会有两套项目方案：</li></ol><ul><li>一套是开发期间的项目，包含了测试文件、测试数据、开发工具、测试工具等相关配置，有利于项目的开发和测试，但是这些文件仅用于开发，发布项目时候需要剔除；</li><li>另一套是部署期间的项目，剔除了那些客户用不到的测试数据测试工具和文件，比较纯净，减少了项目发布后的体积，有利于安装和部署！</li></ul><ol><li>为了满足我们的发布策略，需要新建一个配置文件，命名为<code>webpack.publish.config.js</code>，将<code>webpack.config.js</code>的配置拷贝过去，剔除一些开发配置项即可：</li></ol><ul><li>将<code>devServer</code>节点删掉：</li></ul><pre class='md-fences mock-cm' style='display:block;position:relative'> devServer: {
        hot: true,
        open: true,
        port: 4321
    }</pre><ul><li>将<code>plugins</code>节点下的热更新插件删掉：</li></ul><pre class='md-fences mock-cm' style='display:block;position:relative'> new webpack.HotModuleReplacementPlugin()</pre><ol><li>修改<code>url-loader</code>，将图片放入统一的images文件夹之下：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>{ test: /\.(png|jpg|gif)$/, use: &#39;url-loader?limit=43959&amp;name=images/[name].[ext]&#39; }</pre><p>或者使用<code>img-</code>前缀加上<code>7位的hash名称</code>：</p><pre class='md-fences mock-cm' style='display:block;position:relative'>{ test: /\.(png|jpg|gif)$/, use: &#39;url-loader?limit=43959&amp;name=images/img-[hash:7].[ext]&#39; }</pre><ol><li>在<code>package.json</code>中的script节点下新增<code>dev</code>命令，通过<code>--config</code>指定webpack启动时要读取的配置文件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>&quot;pub&quot;: &quot;webpack --config webpack.publish.config.js&quot;</pre><h2><a name='header-c526' class='md-header-anchor '></a>每次重新构建时候删除dist目录</h2><ol><li>运行<code>cnpm i clean-webpack-plugin --save-dev</code></li><li>在头部引入这个插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>var cleanWebpackPlugin = require(&#39;clean-webpack-plugin&#39;);</pre><ol><li>在<code>plugins</code>节点下使用这个插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>new cleanWebpackPlugin([&#39;dist&#39;])</pre><h2><a name='header-c540' class='md-header-anchor '></a>分离第三方包改造<code>webpack.publish.config.js</code></h2><ol><li>改造entry节点如下：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>entry: {
        app: path.resolve(__dirname, &#39;src/js/main.js&#39;), // 自己代码的入口
        vendors: [&#39;jquery&#39;] // 要分离的第三方包的入口
    }</pre><ol><li>在plugins节点下新增插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>new webpack.optimize.CommonsChunkPlugin({ // 抽离第三方包的插件
        name:&#39;vendors&#39;, // 指定抽离第三方包的入口名称
        filename:&#39;vendors.js&#39; // 抽离出的公共模块的名称
})</pre><ol><li><code>html-webpack-plugin</code>在生成<code>index.html</code>文件的时候，会自动将抽离的第三方包引入进去！</li></ol><h2><a name='header-c555' class='md-header-anchor '></a><a href='https://webpack.js.org/configuration/plugins/#plugins'>优化压缩JS</a></h2><p>在plugins数组中添加：</p><pre class='md-fences mock-cm' style='display:block;position:relative'>new webpack.optimize.UglifyJsPlugin({ // 优化压缩JS
    compress:{
        warnings:false // 移除警告
    }
}),
new webpack.DefinePlugin({ // 设置为产品上线环境，进一步压缩JS代码
    &#39;process.env.NODE_ENV&#39;: &#39;&quot;production&quot;&#39;
})</pre><h2><a name='header-c559' class='md-header-anchor '></a>优化压缩HTML文件</h2><p>在<code>plugins</code>节点下的<code>htmlWebpackPlugin</code>插件中，添加<code>minify</code>子节点：</p><pre class='md-fences mock-cm' style='display:block;position:relative'>minify:{// 压缩HTML代码
    collapseWhitespace:true, // 合并空白字符
    removeComments:true, // 移除注释
    removeAttributeQuotes:true // 移除属性上的引号
}</pre><p>其他优化项请参考：<a href='https://github.com/kangax/html-minifier#options-quick-reference'>html-minifier - github</a></p><h2><a name='header-c565' class='md-header-anchor '></a><a href='https://github.com/webpack-contrib/extract-text-webpack-plugin'>抽取CSS文件</a></h2><ol><li>运行<code>npm install --save-dev extract-text-webpack-plugin</code>安装抽取CSS文件的插件。</li><li>在配置文件中导入插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>const ExtractTextPlugin = require(&quot;extract-text-webpack-plugin&quot;);</pre><ol><li>修改CSS和Sass的loader如下：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>{
    test: /\.css$/, use: ExtractTextPlugin.extract({
        fallback: &quot;style-loader&quot;,
        use: [&quot;css-loader&quot;],
        publicPath: &#39;../&#39; // 设置图片路径
    })
},
{
    test: /\.scss$/, use: ExtractTextPlugin.extract({
        fallback: &quot;style-loader&quot;,
        use: [&#39;css-loader&#39;, &#39;sass-loader&#39;],
        publicPath: &#39;../&#39; // 设置图片路径
    })
}</pre><ol><li>在plugins节点下新增插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>new ExtractTextPlugin(&quot;css/styles.css&quot;), // 抽取CSS文件的插件</pre><h2><a name='header-c584' class='md-header-anchor '></a><a href='https://github.com/NMFR/optimize-css-assets-webpack-plugin'>压缩抽取出来的CSS文件</a></h2><ol><li>运行<code>cnpm i optimize-css-assets-webpack-plugin --save-dev</code>安装插件到开发依赖。</li><li>在配置文件头部导入插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>var OptimizeCssAssetsPlugin = require(&#39;optimize-css-assets-webpack-plugin&#39;);</pre><ol><li>在plugins节点下新增插件：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'> new OptimizeCssAssetsPlugin() // 压缩CSS文件的插件</pre><h2><a name='header-c598' class='md-header-anchor '></a>相关文章</h2><ol><li><a href='http://www.sasschina.com/guide/'>Sass 基础教程</a></li><li><a href='https://github.com/webpack/webpack-dev-server/releases'>webpack-dev-server</a></li><li><a href='http://majing.io/questions/804'>You have not accepted the license agreements of the following </a></li></ol><p></p><h1><a name='header-c611' class='md-header-anchor '></a>移动App第3天</h1><h2><a name='header-c620' class='md-header-anchor '></a>ReactJS简介</h2><ul><li>React 起源于 Facebook 的内部项目，因为该公司对市场上所有 JavaScript MVC 框架，都不满意，就决定自己写一套，用来架设 Instagram 的网站。做出来以后，发现这套东西很好用，<strong>就在2013年5月开源了</strong>。</li><li>由于 React 的设计思想极其独特，属于革命性创新，性能出众，代码逻辑却非常简单。所以，越来越多的人开始关注和使用，认为它可能是将来 Web 开发的主流工具。</li><li>library</li><li>Framework</li></ul><h2><a name='header-c634' class='md-header-anchor '></a>前端三大主流框架</h2><ul><li>Angular.js：出来最早的前端框架，学习曲线比较陡，NG1学起来比较麻烦，NG2开始，进行了一系列的改革，也开始启用组件化了；在NG中，也支持使用TS（TypeScript）进行编程；</li><li>Vue.js：最火的一门前端框架，它是中国人开发的，对我我们来说，文档要友好一些；</li><li>React.js：最流行的一门框架，因为它的设计很优秀；</li><li>windowsPhone 7    7.5   8   10</li></ul><h2><a name='header-c648' class='md-header-anchor '></a>React与vue.js的对比</h2><h3><a name='header-c649' class='md-header-anchor '></a>组件化方面</h3><ol><li>什么是模块化：从 <strong>代码</strong> 的角度，去分析问题，把我们编程时候的业务逻辑，分割到不同的模块中来进行开发，这样能够<strong>方便代码的重用</strong>；</li><li>什么是组件化：从 <strong>UI</strong> 的角度，去分析问题，把一个页面，拆分为一些互不相干的小组件，随着我们项目的开发，我们手里的组件会越来越多，最后，我们如果要实现一个页面，可能直接把现有的组件拿过来进行拼接，就能快速得到一个完整的页面， 这样方<strong>便了UI元素的重用</strong>；<strong>组件是元素的集合体</strong>；</li><li>组件化的好处：</li><li>Vue是如何实现组件化的：.vue 组件模板文件，浏览器不识别这样的.vue文件，所以，在运行前，会把 .vue 预先编译成真正的组件；</li></ol><ul><li>template： UI结构</li><li>script： 业务逻辑和数据</li><li>style： UI的样式</li></ul><ol><li>React如何实现组件化：在React中实现组件化的时候，根本没有 像 .vue 这样的模板文件，而是，直接使用JS代码的形式，去创建任何你想要的组件；</li></ol><ul><li>React中的组件，都是直接在 js 文件中定义的；</li><li>React的组件，并没有把一个组件 拆分为 三部分（结构、样式、业务逻辑），而是全部使用JS来实现一个组件的；（也就是说：结构、样式、业务逻辑是混合在JS里面一起编写出来的）</li></ul><h3><a name='header-c684' class='md-header-anchor '></a>开发团队方面</h3><ul><li>React是由FaceBook前端官方团队进行维护和更新的；因此，React的维护开发团队，技术实力比较雄厚；</li><li>Vue：第一版，主要是有作者 尤雨溪 专门进行维护的，当 Vue更新到 2.x 版本后，也有了一个小团队进行相关的维护和开发；</li></ul><h3><a name='header-c692' class='md-header-anchor '></a>社区方面</h3><ul><li>在社区方面，React由于诞生的较早，所以社区比较强大，一些常见的问题、坑、最优解决方案，文档、博客在社区中都是可以很方便就能找到的；</li><li>Vue是近两年才诞生开源出来的，所以，它的社区相对于React来说，要小巧一些，所以，可能有的一些坑，没人踩过；</li></ul><h3><a name='header-c700' class='md-header-anchor '></a>移动APP开发体验方面</h3><ul><li>Vue，结合 Weex 这门技术，提供了 迁移到 移动端App开发的体验（Weex，目前只是一个 小的玩具， 并没有很成功的 大案例；）</li><li>React，结合 ReactNative，也提供了无缝迁移到 移动App的开发体验（RN用的最多，也是最火最流行的）；</li></ul><h2><a name='header-c708' class='md-header-anchor '></a>为什么要学习React</h2><ol><li>设计很优秀，是基于组件化的，方便我们UI代码的重用；</li><li>开发团队实力强悍，不必担心短更的情况；</li><li>社区强大，很多问题都能找到对应的解决方案；</li><li>提供了无缝转到 ReactNative 上的开发体验，让我们技术能力得到了拓展；增强了我们的核心竞争力</li></ol><h2><a name='header-c722' class='md-header-anchor '></a>React中几个核心的概念</h2><h3><a name='header-c723' class='md-header-anchor '></a>虚拟DOM（Virtual Document Object Model）</h3><ul><li><p>DOM的本质是什么：就是用JS表示的UI元素</p></li><li><p>DOM和虚拟DOM的区别：</p><ul><li>DOM是由浏览器中的JS提供功能，所以我们只能人为的使用 浏览器提供的固定的API来操作DOM对象；</li><li>虚拟DOM：并不是由浏览器提供的，而是我们程序员手动模拟实现的，类似于浏览器中的DOM，但是有着本质的区别；</li></ul></li></ul><ul><li>为什么要实现虚拟DOM：</li><li>什么是React中的虚拟DOM：</li><li>虚拟DOM的目的：
 <img src='images/%E8%99%9A%E6%8B%9FDOM%E5%BC%95%E5%85%A5%E5%9B%BE%E7%89%87.png' alt='虚拟DOM - 表格排序案例' /></li></ul><h3><a name='header-c749' class='md-header-anchor '></a>Diff算法</h3><ul><li>tree diff:新旧DOM树，逐层对比的方式，就叫做 tree diff,每当我们从前到后，把所有层的节点对比完后，必然能够找到那些 需要被更新的元素；</li><li>component diff：在对比每一层的时候，组件之间的对比，叫做 component diff;当对比组件的时候，如果两个组件的类型相同，则暂时认为这个组件不需要被更新，如果组件的类型不同，则立即将旧组件移除，新建一个组件，替换到被移除的位置；</li><li>element diff:在组件中，每个元素之间也要进行对比，那么，元素级别的对比，叫做 element diff；</li><li>key：key这个属性，可以把 页面上的 DOM节点 和 虚拟DOM中的对象，做一层关联关系；
 <img src='images/Diff.png' alt='Diff算法图' /></li></ul><h2><a name='header-c764' class='md-header-anchor '></a>React项目的创建</h2><ol><li>运行 <code>cnpm i react react-dom -S</code> 安装包</li><li>在项目中导入两个相关的包：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>// 1. 在 React 学习中，需要安装 两个包 react  react-dom
// 1.1 react 这个包，是专门用来创建React组件、组件生命周期等这些东西的；
// 1.2 react-dom 里面主要封装了和 DOM 操作相关的包，比如，要把 组件渲染到页面上
import React from &#39;react&#39;
import ReactDOM from &#39;react-dom&#39;</pre><ol><li>使用JS的创建虚拟DOM节点：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    // 2. 在 react 中，如要要创建 DOM 元素了，只能使用 React 提供的 JS API 来创建，不能【直接】像 Vue 中那样，手写 HTML 元素
    // React.createElement() 方法，用于创建 虚拟DOM 对象，它接收 3个及以上的参数
    // 参数1： 是个字符串类型的参数，表示要创建的元素类型
    // 参数2： 是一个属性对象，表示 创建的这个元素上，有哪些属性
    // 参数3： 从第三个参数的位置开始，后面可以放好多的虚拟DOM对象，这写参数，表示当前元素的子节点
    // &lt;div title=&quot;this is a div&quot; id=&quot;mydiv&quot;&gt;这是一个div&lt;/div&gt;

    var myH1 = React.createElement(&#39;h1&#39;, null, &#39;这是一个大大的H1&#39;)

    var myDiv = React.createElement(&#39;div&#39;, { title: &#39;this is a div&#39;, id: &#39;mydiv&#39; }, &#39;这是一个div&#39;, myH1)</pre><ol><li>使用 ReactDOM 把元素渲染到页面指定的容器中：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    // ReactDOM.render(&#39;要渲染的虚拟DOM元素&#39;, &#39;要渲染到页面上的哪个位置中&#39;)
    // 注意： ReactDOM.render() 方法的第二个参数，和vue不一样，不接受 &quot;#app&quot; 这样的字符串，而是需要传递一个 原生的 DOM 对象
    ReactDOM.render(myDiv, document.getElementById(&#39;app&#39;))</pre><h2><a name='header-c783' class='md-header-anchor '></a>JSX语法</h2><ol><li>如要要使用 JSX 语法，必须先运行 <code>cnpm i babel-preset-react -D</code>，然后再 <code>.babelrc</code> 中添加 语法配置；</li><li>JSX语法的本质：还是以 React.createElement 的形式来实现的，并没有直接把 用户写的 HTML代码，渲染到页面上；</li><li>如果要在 JSX 语法内部，书写 JS 代码了，那么，所有的JS代码，必须写到 {} 内部；</li><li>当 编译引擎，在编译JSX代码的时候，如果遇到了<code>&lt;</code>那么就把它当作 HTML代码去编译，如果遇到了 <code>{}</code> 就把 花括号内部的代码当作 普通JS代码去编译；</li><li>在{}内部，可以写任何符合JS规范的代码；</li><li>在JSX中，如果要为元素添加<code>class</code>属性了，那么，必须写成<code>className</code>，因为 <code>class</code>在ES6中是一个关键字；和<code>class</code>类似，label标签的 <code>for</code> 属性需要替换为 <code>htmlFor</code>.</li><li>在JSX创建DOM的时候，所有的节点，必须有唯一的根元素进行包裹；</li><li>如果要写注释了，注释必须放到 {} 内部</li></ol><h2><a name='header-c809' class='md-header-anchor '></a>React中：第一种创建组件的方式</h2><h2><a name='header-c810' class='md-header-anchor '></a>第一种基本组件的创建方式</h2><pre class='md-fences mock-cm' style='display:block;position:relative'>// - 在React中 ，构造函数 就是一个最基本组件
// - 如果想要把组件放到页面中，可以把构造函数名称，当作 组件名称
// ，以HTML 标签形式引入页面中
// - 注意React解析所有标签时候，是以首字母来区分的，如果标签的
// 首字母是大写，则 按照 组件形式去渲染
function Hello(props) {
  return &lt;div&gt;
    {/*&lt;p&gt;React通过构造函数创建的组件---{name}&lt;/p&gt;*/}
    &lt;p&gt;React通过构造函数创建的组件---name:{props.name}---age:{props.age}&lt;/p&gt;
  &lt;/div&gt;
}

ReactDOM.render(
  // &lt;Hello name={name}&gt;&lt;/Hello&gt;
  &lt;Hello&gt;&lt;/Hello&gt;
,document.getElementById(&#39;app&#39;))</pre><ul><li><p>父组件向子组件传递数据</p><pre class='md-fences mock-cm' style='display:block;position:relative'>&lt;Hello name={name}&gt;&lt;/Hello&gt;</pre></li><li><p>属性扩散</p><pre class='md-fences mock-cm' style='display:block;position:relative'>ReactDOM.render(
  // &lt;Hello name={name}&gt;&lt;/Hello&gt;
  &lt;Hello {...person}&gt;&lt;/Hello&gt;
,document.getElementById(&#39;app&#39;))</pre></li><li><p>将组件封装到单独的文件中</p></li></ul><h2><a name='header-c824' class='md-header-anchor '></a>React中：第二种创建组件的方式</h2><h3><a name='header-c825' class='md-header-anchor '></a>了解ES6中class关键字的使用</h3><h3><a name='header-c826' class='md-header-anchor '></a>基于class关键字创建组件</h3><ul><li>使用 class 关键字来创建组件</li></ul><pre class='md-fences mock-cm' style='display:block;position:relative'>class Person extends React.Component{
    // 通过报错提示得知：在class创建的组件中，必须定义一个render函数
    render(){
        // 在render函数中，必须返回一个null或者符合规范的虚拟DOM元素
        return &lt;div&gt;
            &lt;h1&gt;这是用 class 关键字创建的组件！&lt;/h1&gt;
        &lt;/div&gt;;
    }
}</pre><h2><a name='header-c832' class='md-header-anchor '></a>两种创建组件方式的对比</h2><ol><li>用构造函数创建出来的组件：专业的名字叫做“无状态组件”</li><li>用class关键字创建出来的组件：专业的名字叫做“有状态组件”</li></ol><blockquote><p>用构造函数创建出来的组件，和用class创建出来的组件，这两种不同的组件之间的<strong>本质区别就是</strong>：有无state属性！！！
有状态组件和无状态组件之间的本质区别就是：有无state属性！</p></blockquote><h2><a name='header-c617' class='md-header-anchor '></a>一个小案例，巩固有状态组件和无状态组件的使用</h2><h3><a name='header-c897' class='md-header-anchor '></a>通过for循环生成多个组件</h3><ol><li>数据：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>CommentList = [
    { user: &#39;张三&#39;, content: &#39;哈哈，沙发&#39; },
    { user: &#39;张三2&#39;, content: &#39;哈哈，板凳&#39; },
    { user: &#39;张三3&#39;, content: &#39;哈哈，凉席&#39; },
    { user: &#39;张三4&#39;, content: &#39;哈哈，砖头&#39; },
    { user: &#39;张三5&#39;, content: &#39;哈哈，楼下山炮&#39; }
]</pre><h3><a name='header-c903' class='md-header-anchor '></a>style样式</h3><h2><a name='header-c904' class='md-header-anchor '></a>使用CSS模块化</h2><ol><li>可以在webpack.config.js中为css-loader启用模块化：
<code>css-loader?modules&amp;localIdentName=[name]_[local]-[hash:8]</code></li><li>使用<code>:global()</code>定义全局样式</li></ol><h2><a name='header-c913' class='md-header-anchor '></a>总结</h2><p>理解React中虚拟DOM的概念
理解React中三种Diff算法的概念
使用JS中createElement的方式创建虚拟DOM
使用ReactDOM.render方法
使用JSX语法并理解其本质
掌握创建组件的两种方式
理解有状态组件和无状态组件的本质区别
理解props和state的区别</p><h2><a name='header-c923' class='md-header-anchor '></a>相关文章</h2><ul><li><a href='http://www.cnblogs.com/tim100/p/6050514.html'>React数据流和组件间的沟通总结</a></li><li><a href='https://segmentfault.com/q/1010000005876655/a-1020000005876751'>单向数据流和双向绑定各有什么优缺点？</a></li><li><a href='https://www.zhihu.com/question/29504639?sort=created'>怎么更好的理解虚拟DOM?</a></li><li><a href='http://www.css88.com/react/index.html'>React中文文档 - 版本较低</a></li><li><a href='http://blog.csdn.net/yczz/article/details/49886061'>React 源码剖析系列 － 不可思议的 react diff</a></li><li><a href='http://www.infoq.com/cn/articles/react-dom-diff?from=timeline&isappinstalled=0'>深入浅出React（四）：虚拟DOM Diff算法解析</a></li><li><a href='http://www.cocoachina.com/webapp/20150721/12692.html'>一看就懂的ReactJs入门教程（精华版）</a></li><li><a href='http://www.ruanyifeng.com/blog/2016/06/css_modules.html'>CSS Modules 用法教程</a></li><li><a href='http://blog.csdn.net/itzhongzi/article/details/66045880'>将MarkDown转换为HTML页面</a></li><li><a href='https://jingyan.baidu.com/article/0320e2c1c9cf0e1b87507b26.html'>win7命令行 端口占用 查询进程号 杀进程</a>目</li></ul><p></p><h1><a name='header-c10' class='md-header-anchor '></a>移动App第4天</h1><h2><a name='header-c1070' class='md-header-anchor '></a>组件的生命周期</h2><ul><li><p>概念：在组件创建、到加载到页面上运行、以及组件被销毁的过程中，总是伴随着各种各样的事件，这些在组件特定时期，触发的事件，统称为 组件的生命周期；</p></li><li><p>组件生命周期分为三部分：</p><ul><li><strong>组件创建阶段</strong>：组件创建阶段的生命周期函数，有一个显著的特点：创建阶段的生命周期函数，在组件的一辈子中，只执行一次；</li></ul><blockquote><p>componentWillMount: 组件将要被挂载，此时还没有开始渲染虚拟DOM
render：第一次开始渲染真正的虚拟DOM，当render执行完，内存中就有了完整的虚拟DOM了
componentDidMount: 组件完成了挂载，此时，组件已经显示到了页面上，当这个方法执行完，组件就进入都了 运行中 的状态</p></blockquote><ul><li><strong>组件运行阶段</strong>：也有一个显著的特点，根据组件的state和props的改变，有选择性的触发0次或多次；</li></ul><blockquote><p>componentWillReceiveProps: 组件将要接收新属性，此时，只要这个方法被触发，就证明父组件为当前子组件传递了新的属性值；
shouldComponentUpdate: 组件是否需要被更新，此时，组件尚未被更新，但是，state 和 props 肯定是最新的
componentWillUpdate: 组件将要被更新，此时，尚未开始更新，内存中的虚拟DOM树还是旧的
render: 此时，又要重新根据最新的 state 和 props 重新渲染一棵内存中的 虚拟DOM树，当 render 调用完毕，内存中的旧DOM树，已经被新DOM树替换了！此时页面还是旧的
componentDidUpdate: 此时，页面又被重新渲染了，state 和 虚拟DOM 和 页面已经完全保持同步</p></blockquote><ul><li><strong>组件销毁阶段</strong>：也有一个显著的特点，一辈子只执行一次；</li></ul><blockquote><p>componentWillUnmount: 组件将要被卸载，此时组件还可以正常使用；</p></blockquote></li></ul><p><a href='https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA'>vue中的生命周期图</a>
<a href='http://www.race604.com/react-native-component-lifecycle/'>React Native 中组件的生命周期</a></p><h3><a name='header-c12' class='md-header-anchor '></a>defaultProps</h3><blockquote><p>在组件创建之前，会先初始化默认的props属性，这是全局调用一次，严格地来说，这不是组件的生命周期的一部分。在组件被创建并加载候，首先调用 constructor 构造器中的 this.state = {}，来初始化组件的状态。</p></blockquote><p>React生命周期的回调函数总结成表格如下：</p><p>组件生命周期的执行顺序：</p><ul><li>Mounting：</li></ul><ul><li>constructor()</li><li>componentWillMount()</li><li>render()</li><li>componentDidMount()</li></ul><ul><li>Updating：</li></ul><ul><li>componentWillReceiveProps(nextProps)</li><li>shouldComponentUpdate(nextProps, nextState)</li><li>componentWillUpdate(nextProps, nextState)</li><li>render()</li><li>componentDidUpdate(prevProps, prevState)</li></ul><ul><li>Unmounting：</li></ul><ul><li>componentWillUnmount()</li></ul><h2><a name='header-c1169' class='md-header-anchor '></a>通过Counter计数器的小案例 - 了解生命周期函数</h2><ol><li><p>给组件设置默认属性：</p><pre class='md-fences mock-cm' style='display:block;position:relative'>//导入组件
import Counter from &#39;./components/Counter.jsx&#39;

ReactDOM.render(&lt;div&gt;
  {/* 规定，每个用户在使用 组件的时候，必须传递一个 默认的 数量值，最为 组件初始化的 数据 */}
   &lt;Counter initcount={0}&gt;&lt;/Counter&gt; 
&lt;/div&gt;, document.getElementById(&#39;app&#39;))</pre></li></ol><p>   ​</p><ol><li>给属性进行类型校验，需要先运行<code>cnpm i prop-types --save</code></li></ol><h2><a name='header-c1181' class='md-header-anchor '></a>组件初始化时生命周期事件总结</h2><ol><li>componentWillMount：</li><li>render：</li><li>componentDidMount：</li><li>注意：在render函数中，不能调用<code>setState()</code>方法</li></ol><h2><a name='header-c1195' class='md-header-anchor '></a>通过原生的方式获取元素并绑定事件</h2><h2><a name='header-c1196' class='md-header-anchor '></a>React中使用ref属性获取DOM元素引用</h2><h2><a name='header-c1197' class='md-header-anchor '></a>使用React中的事件，绑定count自增</h2><h2><a name='header-c1198' class='md-header-anchor '></a>组件运行中事件的对比</h2><ol><li>shouldComponentUpdate：</li><li>componentWillUpdate：</li><li>render：</li><li>componentDidUpdate：</li></ol><h2><a name='header-c1212' class='md-header-anchor '></a>绑定this并传参的三种方式</h2><ol><li>在事件中绑定this并传参：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    &lt;input type=&quot;button&quot; value=&quot;在事件中绑定this并传参&quot; onClick={this.handleMsg1.bind(this, &#39;🍕&#39;, &#39;🍟&#39;)} /&gt;

    // 在事件中绑定this并传参
    handleMsg1(arg1, arg2) {
        console.log(this);
        // 此时this是个null
        this.setState({
            msg: &#39;在事件中绑定this并传参：&#39; + arg1 + arg2
        });
    }</pre><ol><li>在构造函数中绑定this并传参:</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    // 修改构造函数中的代码：
    this.handleMsg2 = this.handleMsg2.bind(this, &#39;🚗&#39;, &#39;🚚&#39;);

    &lt;input type=&quot;button&quot; value=&quot;在构造函数中绑定this并传参&quot; onClick={this.handleMsg2} /&gt;

    // 在构造函数中绑定this并传参
    handleMsg2(arg1, arg2) {
        this.setState({
            msg: &#39;在构造函数中绑定this并传参：&#39; + arg1 + arg2
        });
    }</pre><ol><li>用箭头函数绑定this并传参：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    &lt;input type=&quot;button&quot; value=&quot;用箭头函数绑定this并传参&quot; onClick={() =&gt; { this.handleMsg3(&#39;👩&#39;, &#39;👰&#39;) }} /&gt;

    // 用箭头函数绑定this并传参
        handleMsg3(arg1, arg2) {
            this.setState({
                msg: &#39;用箭头函数绑定this并传参：&#39; + arg1 + arg2
            });
        }</pre><h2><a name='header-c1228' class='md-header-anchor '></a>绑定文本框与state中的值</h2><ol><li>在Vue.js中，默认可以通过<code>v-model</code>指令，将表单控件和我们的<code>data</code>上面的属性进行双向数据绑定，数据变化和页面之间的变化是同步的！</li><li>在React.js中，默认没有提供双向数据绑定这一功能，默认的，只能把<code>state</code>之上的数据同步到界面的控件上，但是不能默认实现把界面上数据的改变，同步到<code>state</code>之上，需要程序员手动调用相关的事件，来进行逆向的数据传输！</li><li>绑定文本框和state的值：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>    {/*只要将value属性，和state上的状态进行绑定，那么，这个表单元素就变成了受控表单元素，这时候，如果没有调用相关的事件，是无法手动修改表单元素中的值的*/}
    &lt;input style={{ width: &#39;100%&#39; }} ref=&quot;txt&quot; type=&quot;text&quot; value={this.state.msg} onChange={this.handleTextChange} /&gt;

    // 这是文本框内容改变时候的处理函数
    handleTextChange = () =&gt; {
        this.setState({
            msg: this.refs.txt.value
        });
    }</pre><ol><li>注意<code>setState的一个问题</code>：</li></ol><pre class='md-fences mock-cm' style='display:block;position:relative'>// 保存最新的state状态值，在保存的时候，是异步地进行保存的，所以，如果想要获取最新的，刚刚保存的那个状态，需要通过回掉函数的形式去获取最新state
this.setState({
    msg: this.refs.txt.value
    // msg: e.target.value
}, function () {
    // 获取最新的state状态值
    console.log(this.state.msg);
});</pre><h2><a name='header-c1245' class='md-header-anchor '></a>发表评论案例</h2><h2><a name='header-c1246' class='md-header-anchor '></a>扩展</h2><h3><a name='header-c1247' class='md-header-anchor '></a>context特性</h3><p>记住一串单词组合<code>getChildContextTypes</code>
前3个、后3个、后两个
一个方法、两个静态属性</p><p></p><h2><a name='header-c1254' class='md-header-anchor '></a>相关文章</h2><p><a href='https://facebook.github.io/react/docs/typechecking-with-proptypes.html'>类型校验</a>
<a href='https://reactjs.org/docs/animation.html#high-level-api-reactcsstransitiongroup'>Animation Add-Ons</a></p><p><a href='https://reactjs.org/docs/animation.html#high-level-api-reactcsstransitiongroup'>Animation Add-Ons</a>
<a href='https://www.cnblogs.com/libin-1/p/5864376.html'>移动端 关于 键盘将input 框 顶上去的解决思路---个人见解</a></p><h1><a name='header-c1112' class='md-header-anchor '></a>ReactNative项目</h1><p></p></div>
</body>
</html>